#import "Status.h"
#import "Followee.h"
#import "DBConnection.h"
#import "REString.h"
#import "StringUtil.h"
#import "TimeUtils.h"
#import "Statement.h"
#import "GuaziAppDelegate.h"

@interface Status (Private)
- (void)insertDB;
@end

// sort function of DM timeline
//
static NSInteger sortByDateDesc(id a, id b, void *context)
{
    Status* dma = (Status*)a;
    Status* dmb = (Status*)b;
    int diff = dmb.createdAt - dma.createdAt;
    if (diff > 0)
        return -1;
    else if (diff < 0)
        return 1;
    else
        return 0;
}

@implementation Status

//@synthesize user;
@synthesize source;
@synthesize favorited;
@synthesize truncated;
@synthesize forwardCount;
@synthesize remarkCount;

@synthesize inReplyToStatusId;
@synthesize inReplyToUserId;
@synthesize inReplyToScreenName;

@synthesize originStatusId;
@synthesize ownerUserId;

@synthesize originPicture;
@synthesize smallPicture;
@synthesize middlePicture;
@synthesize smallPictureSize;
@synthesize originStatus;


- (void)dealloc
{
    [inReplyToScreenName release];
    [source release];
    [originPicture release];
    [smallPicture release];
    [middlePicture release];
    [originStatus release];
  	[super dealloc];
}



- (CGFloat) cellHeight
{
    CGFloat height = super.cellHeight;
    if ( self.smallPicture && [self.smallPicture length] > 0 ) {
        height = height + 100;
    }
    
    return height;
}


- (Status*)initWithJsonDictionary:(NSDictionary*)dic type:(TweetType)aType
{
	self = [super init];
    
    type = aType;
    cellType = TWEET_CELL_TYPE_NORMAL;
    
	tweetId           = [[dic objectForKey:@"id"] longLongValue];
    stringOfCreatedAt   = [dic objectForKey:@"created_at"];
    if ((id)stringOfCreatedAt == [NSNull null]) {
        stringOfCreatedAt = @"";
    }
	else {
		NSDateFormatter* formatter = [[NSDateFormatter alloc] init];
		[formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss" ];
		NSDate* d = [formatter dateFromString:stringOfCreatedAt];
		createdAt = [d timeIntervalSince1970];
        [formatter release];
	}
	
   //favorited = [dic objectForKey:@"favorited"] == [NSNull null] ? 0 : [[dic objectForKey:@"favorited"] boolValue];
    //truncated = [dic objectForKey:@"truncated"] == [NSNull null] ? 0 : [[dic objectForKey:@"truncated"] boolValue];
    NSString* s = (NSString*) [dic objectForKey:@"favorited"];
	if ( [@"YES" compare:s] == NSOrderedSame ) favorited = true;
	else favorited = false;
	
    NSString *tweet = [dic objectForKey:@"text"];

    if ((id)tweet == [NSNull null]) {
        text = @"";
    }
    else {
        tweet = [[tweet unescapeHTML] stringByReplacingOccurrencesOfString:@"\n" withString:@" "];
        text  = [[tweet stringByReplacingOccurrencesOfString:@"\r" withString:@" "] retain];
    }
    
    forwardCount = [dic objectForKey:@"forwardCount"]==[NSNull null] ? 0 : [[dic objectForKey:@"forwardCount"] intValue];
    remarkCount = [dic objectForKey:@"remarkCount"]==[NSNull null] ? 0 : [[dic objectForKey:@"remarkCount"] intValue];

    // parse source parameter
    NSString *src = [dic objectForKey:@"source"];
    if (src == nil) {
        source = @"";
    }
    else if ((id)src == [NSNull null]) {
        source = @"";
    }
    else {
        NSRange r = [src rangeOfString:@"<a href"];
        if (r.location != NSNotFound) {
            NSRange start = [src rangeOfString:@"\">"];
            NSRange end   = [src rangeOfString:@"</a>"];
            if (start.location != NSNotFound && end.location != NSNotFound) {
                r.location = start.location + start.length;
                r.length = end.location - r.location;
                source = [[src substringWithRange:r] retain];
            }
        }
        else {
            source = [src retain];
        }
    }
    
    inReplyToStatusId   = [dic objectForKey:@"in_reply_to_status_id"]   == [NSNull null] ? 0 : [[dic objectForKey:@"in_reply_to_status_id"] longLongValue];
    inReplyToUserId     = [dic objectForKey:@"in_reply_to_user_id"]     == [NSNull null] ? 0 : [[dic objectForKey:@"in_reply_to_user_id"] intValue];
    inReplyToScreenName = [dic objectForKey:@"in_reply_to_screen_name"];
    if ((id)inReplyToScreenName == [NSNull null]) inReplyToScreenName = @"";
    if (inReplyToScreenName == nil) inReplyToScreenName = @"";
    [inReplyToScreenName retain];
	
	NSDictionary* userDic = [dic objectForKey:@"user"];
	if (userDic!=nil && [userDic isKindOfClass:[NSDictionary class]]) {
        user = [User userWithJsonDictionary:userDic];
    }
	
	id object = [dic objectForKey:@"retweeted_status"];
	if ( object != nil && [object isKindOfClass:[NSDictionary class]] ) {
        NSDictionary* originStatusDic = (NSDictionary*) object;
        self.originStatus = [Status statusWithJsonDictionary:originStatusDic type:aType];
		originStatusId = originStatus.statusId;
	}
	
	groupId = [dic objectForKey:@"group_id"] == [NSNull null] ? 0 : [[dic objectForKey:@"group_id"] longLongValue];
    ownerUserId = [GuaziAppDelegate getAppDelegate].user.userId;
    
    object = [dic objectForKey:@"original_pic"];
    if ( object && object != [NSNull null] ) {
        self.originPicture = (NSString*) object;
    }
    
    object = [dic objectForKey:@"bmiddle_pic"];
    if ( object && object != [NSNull null] ) {
        self.middlePicture = (NSString*) object;
    }
    
    object = [dic objectForKey:@"thumbnail_pic"];
    if ( object && object != [NSNull null] ) {
        self.smallPicture = (NSString*) object;
    }
    
    [self updateAttribute];
    unread = true;

	return self;
}


- (Status*)initWithSearchResult:(NSDictionary*)dic
{
	self = [super init];
    
    type = TWEET_TYPE_SEARCH_RESULT;
    cellType = TWEET_CELL_TYPE_NORMAL;
    
	tweetId           = [[dic objectForKey:@"id"] longLongValue];
    stringOfCreatedAt   = [dic objectForKey:@"created_at"];
    if ((id)stringOfCreatedAt == [NSNull null]) {
        stringOfCreatedAt = @"";
    }
    
    NSString *tweet = [dic objectForKey:@"text"];
    
    if ((id)tweet == [NSNull null]) {
        text = @"";
    }
    else {
        tweet = [[tweet  unescapeHTML] stringByReplacingOccurrencesOfString:@"\n" withString:@" "];
        text  = [[tweet stringByReplacingOccurrencesOfString:@"\r" withString:@" "] retain];
    }
    
    // parse source parameter
    source = @"";
    
    user = [User userWithSearchResult:dic];
    
    [self updateAttribute];
    
	return self;
}


+ (Status*)statusWithJsonDictionary:(NSDictionary*)dic type:(TweetType)type
{
	return [[[Status alloc] initWithJsonDictionary:dic type:type] autorelease];
}


+ (Status*)statusWithSearchResult:(NSDictionary*)dic
{
	return [[[Status alloc] initWithSearchResult:dic] autorelease];
}


- (id)copyWithZone:(NSZone *)zone
{
    Status *dist = [super copyWithZone:zone];
    
    dist.source     = source;
    dist.favorited  = favorited;
    dist.truncated  = truncated;
    dist.remarkCount = remarkCount;
    dist.forwardCount = forwardCount;

    dist.inReplyToStatusId   = inReplyToStatusId;
    dist.inReplyToUserId     = inReplyToUserId;
    dist.inReplyToScreenName = inReplyToScreenName;
	
	dist.originStatusId = originStatusId;
    dist.groupId = groupId;
    dist.ownerUserId = ownerUserId;
    
    dist.originPicture = self.originPicture;
    dist.smallPicture = self.smallPicture;
    dist.middlePicture = self.middlePicture;
    
    return dist;
}

int sTextWidth[] = {
    CELL_WIDTH,
    USER_CELL_WIDTH,
    DETAIL_CELL_WIDTH,
};

- (void)updateAttribute
{
    [super updateAttribute];
    int textWidth = sTextWidth[cellType];

    if (accessoryType == UITableViewCellAccessoryDetailDisclosureButton) {
        textWidth -= DETAIL_BUTTON_WIDTH;
    }
    else if (cellType == TWEET_CELL_TYPE_DETAIL) {
        textWidth -= H_MARGIN;
    }
    else {
        textWidth -= INDICATOR_WIDTH;
    }
    // Calculate text bounds and cell height here
    //
    [self calcTextBounds:textWidth];
}

+ (Status*)statusWithId:(sqlite_int64)aStatusId
{
	sqlite3* theDatabase = [DBConnection getDatabase];
	char* sql = "SELECT * FROM statuses WHERE id = ?";
	
    Statement *stmt = [[Statement alloc] initWithDB:theDatabase sql:sql];
	Status* s = nil;
    [stmt bindInt64:aStatusId forIndex:1];
    if ([stmt step] == SQLITE_ROW) {
		s = [Status statusWithStatement:stmt type:TWEET_TYPE_FRIENDS];
    }
    
    [stmt release];
    return s;
}


+ (Status*)statusWithStatement:(Statement*)stmt type:(TweetType)type
{
    // sqlite3 statement should be:
    //  SELECT * FROM messsages
    //
    Status *s               = [[[Status alloc] init] autorelease];
    
    s.statusId              = [stmt getInt64:0];
    s.text                  = [stmt getString:3];
    s.createdAt             = [stmt getInt32:4];
    s.source                = [stmt getString:5];
    s.favorited             = [stmt getInt32:6];
    s.truncated             = [stmt getInt32:7];
    s.inReplyToStatusId     = [stmt getInt64:8];
    s.inReplyToUserId       = [stmt getInt32:9];
    s.inReplyToScreenName   = [stmt getString:10];
	s.originStatusId		= [stmt getInt64:11];
	s.groupId				= [stmt getInt64:12];
    s.ownerUserId           = [stmt getInt64:13];
    s.originPicture         = [stmt getString:14];
    s.smallPicture          = [stmt getString:15];
    s.middlePicture         = [stmt getString:16];
    s.remarkCount           = [stmt getInt32:17];
    s.forwardCount          = [stmt getInt32:18];
	
    s.user = [User userWithId:[stmt getInt64:2]];

    if (s.user == nil) {
        return nil;
    }

    s.unread                = false;
    s.type                  = type;

    s.cellType = TWEET_CELL_TYPE_NORMAL;
    [s updateAttribute];
    
    return s;
}


+ (BOOL)isExists:(sqlite_int64)aStatusId type:(TweetType)aType
{
	sqlite3* theDatabase = [DBConnection getDatabase];
	char* sql = "SELECT id FROM statuses WHERE id=? and type=?";
	
    Statement *stmt = [[Statement alloc] initWithDB:theDatabase sql:sql];
    [stmt bindInt64:aStatusId forIndex:1];
    [stmt bindInt32:aType forIndex:2];
    
    BOOL result = ([stmt step] == SQLITE_ROW) ? true : false;
    [stmt release];
    return result;
}


- (BOOL)hasConversation
{
    sqlite_int64 inReplyTo = inReplyToStatusId;
    
    if (inReplyTo == 0) inReplyTo = -1;

//    static char *sql = "SELECT count(*) FROM statuses WHERE id = ? OR in_reply_to_status_id = ?";
    static char *sql = "SELECT count(*) FROM statuses WHERE id = ?";
	
	sqlite3* theDatabase = [DBConnection getDatabase];
	Statement* stmt = [[Statement alloc] initWithDB:theDatabase sql:sql];
    [stmt bindInt64:inReplyToStatusId       forIndex:1];
//    [stmt bindInt64:tweetId                 forIndex:2];
    [stmt step];
        
    NSInteger i = [stmt getInt32:0];
    [stmt release];
    return i;
}


- (int)getConversation:(NSMutableArray*)messages
{
    NSMutableDictionary *hash = [NSMutableDictionary dictionary];
    
    NSMutableArray *idArray = [NSMutableArray array];
    NSMutableArray *replyArray = [NSMutableArray array];
    
    int count = 1;
    [messages addObject:self];
    [idArray addObject:[NSNumber numberWithLongLong:self.tweetId]];
    [replyArray addObject:[NSNumber numberWithLongLong:self.inReplyToStatusId]];
     
    [hash setObject:self forKey:[NSString stringWithFormat:@"%lld", self.tweetId]];
    
    INIT_STOPWATCH(s);
	
	sqlite3* theDatabase = [DBConnection getDatabase];
    
    while ([idArray count]) {

        NSString *replies = [idArray componentsJoinedByString:@","];
        NSString *ids = [replyArray componentsJoinedByString:@","];
        
        [idArray removeAllObjects];
        [replyArray removeAllObjects];

        NSString *sql = [NSString stringWithFormat:@"SELECT * FROM statuses WHERE id IN (%@) OR in_reply_to_status_id IN (%@)", ids, replies];
		Statement* stmt = [[Statement alloc] initWithDB:theDatabase sql:(char*)[sql UTF8String]];
        
        //NSLog(@"Exec %@", sql);
        while ([stmt step] == SQLITE_ROW) {
            NSString *idStr = [NSString stringWithFormat:@"%lld", [stmt getInt64:0]];
            //NSLog(@"Found %@", idStr);
            if (![hash objectForKey:idStr]) {
                Status *s = [Status statusWithStatement:stmt type:TWEET_TYPE_FRIENDS];
                [hash setObject:s forKey:idStr];
                [messages addObject:s];
                [idArray addObject:[NSNumber numberWithLongLong:s.tweetId]];
                if (s.inReplyToStatusId) {
                    [replyArray addObject:[NSNumber numberWithLongLong:s.inReplyToStatusId]];
                }
                
                // Up to 100 messages
                if (++count >= 100) break;
            }
        }
        [stmt release];
    }
    
    LAP(s, @"Decode conversation");
    
    [messages sortUsingFunction:sortByDateDesc context:nil];    
    
    return count;
}


- (void) insertDB
{
    [self insertDB:@"statuses"];
}


- (void)insertDB:(NSString*)tablename
{
	
    [user updateDB:YES withName:NO withAccount:NO];

	sqlite3* db = [DBConnection getDatabase];
    NSString* sql = [NSString stringWithFormat:@"REPLACE INTO %@ VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", tablename];
    Statement *stmt = [[Statement alloc] initWithDB:db sql:(char*)[sql UTF8String]];
    [stmt bindInt64:tweetId    forIndex:1];
    if (type == TWEET_TYPE_FAVORITES) {
        [stmt bindInt32:TWEET_TYPE_FRIENDS forIndex:2];
    }
    else {
        [stmt bindInt32:type        forIndex:2];
    }

    [stmt bindInt64:user.userId forIndex:3];
    
    [stmt bindString:text       forIndex:4];
    [stmt bindInt32:createdAt   forIndex:5];
    [stmt bindString:source     forIndex:6];
    [stmt bindInt32:favorited   forIndex:7];
    [stmt bindInt32:truncated   forIndex:8];
    
    [stmt bindInt64:inReplyToStatusId    forIndex:9];
    [stmt bindInt32:inReplyToUserId      forIndex:10];
    [stmt bindString:inReplyToScreenName forIndex:11];
	
	[stmt bindInt64:originStatusId forIndex:12];
	[stmt bindInt64:groupId forIndex:13];
    [stmt bindInt64:ownerUserId forIndex:14];
    
    [stmt bindString:originPicture forIndex:15];
    [stmt bindString:smallPicture forIndex:16];
    [stmt bindString:middlePicture forIndex:17];
    [stmt bindInt32:remarkCount forIndex:18];
    [stmt bindInt32:forwardCount forIndex:19];
	
    if ([stmt step] != SQLITE_DONE) {
        [GuaziAppDelegate showAlert:@"数据库访问错误! status.insertDB"];
    }
	
    [stmt release];

    if (type == TWEET_TYPE_FRIENDS) {
        [Followee insertDB:user];
    }
}





- (void)insertDBIfFollowing
{
	sqlite3* db = [DBConnection getDatabase];
	char* sql = "SELECT user_id FROM followees where user_id = ?";
    Statement *stmt = [[Statement alloc] initWithDB:db sql:sql];
    [stmt bindInt64:user.userId forIndex:1];
    if ([stmt step] == SQLITE_ROW) {
        [self insertDB];
    }
	[stmt release];
}


- (void)deleteFromDB
{
	sqlite3* db = [DBConnection getDatabase];
	char* sql = "DELETE FROM statuses WHERE id = ?";
    Statement *stmt = [[Statement alloc] initWithDB:db sql:sql];
    [stmt bindInt64:tweetId forIndex:1];
    [stmt step]; // ignore error
    [stmt release];
}

- (void)updateFavoriteState
{
	sqlite3* db = [DBConnection getDatabase];
	char* sql = "UPDATE statuses SET favorited = ? WHERE id = ?";
    Statement *stmt = [[Statement alloc] initWithDB:db sql:sql];

    [stmt bindInt32:favorited forIndex:1];
    [stmt bindInt64:tweetId forIndex:2];
    [stmt step]; // ignore error
    [stmt release];
}

+ (void) updateStatus:(long long)statusId remarkCount:(NSInteger)remarkCount forwardCount:(NSInteger)forwardCount
{
	sqlite3* db = [DBConnection getDatabase];
	char* sql = "UPDATE statuses SET remark_count = ?, forward_count = ? WHERE id = ?";
    Statement *stmt = [[Statement alloc] initWithDB:db sql:sql];
    [stmt bindInt32:remarkCount forIndex:1];
    [stmt bindInt32:forwardCount forIndex:2];
    [stmt bindInt64:statusId forIndex:3];
    [stmt step]; // ignore error
    [stmt release];
}


- (NSString*) sourceDescription
{
	if ( source == nil ) return @"";
	else if ( [source compare:@"WEB"] == NSOrderedSame ) return @"瓜子网";
	else if ( [source compare:@"MB"] == NSOrderedSame ) return @"手机";
	else if ( [source compare:@"IPHONE"] == NSOrderedSame ) return @"iphone客户端";
	else if ( [source compare:@"ANDROID"] == NSOrderedSame ) return @"android客户端";
	else return source;
}

@end
